package com.llb666.e.shop.infracore.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置.
 *
 * @author llb666
 * @date 2022/8/16 18:08
 */
@Configuration
@EnableAsync
public class ExecutorConfig {

    /**
     * 核心线程数.
     */
    @Value("${llb.async.executor.core-pool-size:8}")
    private Integer corePoolSize;
    /**
     * 最大线程数.
     */
    @Value("${llb.async.executor.max-pool-size:32}")
    private Integer maxPoolSize;
    /**
     * 队列最大长度.
     */
    @Value("${llb.async.executor.queue-capacity:64}")
    private Integer queueCapacity;
    /**
     * 线程池维护线程所允许的空闲时间.
     */
    @Value("${llb.async.executor.keep-alive-seconds:300000}")
    private Integer keepAliveSeconds;
    /**
     * 线程池名前缀.
     */
    @Value("${llb.async.executor.thread-name-prefix:shop-task}")
    private String threadNamePrefix;
    /**
     * 完成任务自动关闭.
     */
    @Value("${llb.async.executor.wait-for-tasks-to-complete-on-shutdown:true}")
    private Boolean waitForTasksToCompleteOnShutdown;
    /**
     * 任务等待时间：超过这个时间还没有销毁，就强制销毁，以确保应用最后能够关闭而不是被阻塞.
     */
    @Value("${llb.async.executor.await-termination-seconds:5}")
    private Integer awaitTerminationSeconds;

    @Bean(name = "shopServiceExecutor")
    public Executor asyncServiceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
        /*
         * 配置决绝策略：
         * AbortPolicy: 默认的拒绝策略，直接抛出RejectedException异常.
         * CallerRunsPolicy： 既不会抛弃任务，也不会抛出异常，而是将任务回推到调用者.
         * DiscardPolicy:直接丢弃任务，不予处理也不抛出异常。如果允许丢弃任务，是最好的处理策略.
         * DiscardOldestPolicy:抛弃队列中等待最久的任务，然后把当前任务加入队列尝试再次提交（可能会再次失败，导致重复）.
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        return executor;
    }
}
